package interceptor

import (
	. "Go-Easy/pkg/config"
	. "Go-Easy/pkg/log"
	. "Go-Easy/pkg/sentinel"
	"context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/peer"
	"google.golang.org/grpc/status"
)

type AuthenticationFunction func(ctx context.Context) error

type easyInterceptor struct {
	ServiceName string
	cfg         Config_Service
	authFunc    AuthenticationFunction
}

func NewEasyInterceptor(ServiceName string, authFunc AuthenticationFunction) *easyInterceptor {
	return &easyInterceptor{
		ServiceName: ServiceName,
		cfg:         ServiceMap[ServiceName],
		authFunc:    authFunc,
	}
}

//思考:是否可以用栈的方式实现拦截器中函数调用？
//gatekeeper第一个入栈，之后自定义方法，最后是日志

//一元拦截器,函数参数说明
//ctx - 上下文
//req - 入参
//info - Unray调用的信息，主要是方法名
//handler - 正常处理的函数
//resp - 出参
//err - 错误
func (e *easyInterceptor) UnaryInterceptor() grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		//入站流量限制
		if e.cfg.TrafficInboundRestrict != "" {
			if err = TrafficInboundRestrict(e.cfg.TrafficInboundRestrict); err != nil {
				return nil, status.Error(codes.ResourceExhausted, err.Error())
			}
		}

		//身份验证
		if err = e.authFunc(ctx); err != nil {
			return nil, status.Error(codes.Unauthenticated, err.Error())
		}

		//处理请求
		resp, err = handler(ctx, req)

		//记录日志
		p, _ := peer.FromContext(ctx)
		MyMicroServicelogger(p.Addr.String(), info.FullMethod, resp, err)

		//返回response、error
		return resp, err
	}
}
